// =======================================
// Title  : 环形缓冲区类 
// Author : 靳普诏 
// Note   : 第2次
// =======================================

#include "abc_ring_buff.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// #include <malloc.h>


/*------------------- _TBuffer 类型 begin --------------------*/

typedef struct
{
    // ------ 公开数据成员 ------

    // ------ 保护数据成员 ------

    // ------ 私有数据成员 ------
    Byte*           Buffer;
    Byte*           BufferEnd;
    Byte*           Pop;
    Byte*           Push;
    Int32           PopSize;
    Int32           PushSize;
    Int32           MaxSize;
} _TBuffer, *_PBuffer;

// ---------------- 私有函数 ----------------


// 读取当前已经使用过的大小
static DWord L_UsedSize(_TBuffer* _this)
{
    return _this->PushSize - _this->PopSize;
}

// 读取当前剩余的大小
static DWord L_UnusedSize(_TBuffer* _this)
{
    return _this->MaxSize - (_this->PushSize - _this->PopSize);
}

// 判断当前项是否为空
static Bool L_IsEmpty(_TBuffer* _this)
{
    return _this->PopSize == _this->PushSize;
}

// 判断当前项是否为满
static Bool L_IsFull(_TBuffer* _this)
{
    return _this->PushSize - _this->PopSize == _this->MaxSize;
}

// Push

/**
 * @brief 压入一串数据
 * @param _this 
 * @param from 数据头地址
 * @param size 数据长度
 * @return Int32 成功压入的数据长度
 */
static Int32 L_DoPush_Memory(_TBuffer* _this, const Byte* from, Int32 data_size)
{
    Int32 result = 0;
    Int32 avail_size = L_UnusedSize(_this);
    
    if (avail_size > 0)
    {
        if (avail_size < data_size)
            data_size = avail_size;
        Int32 temp = _this->BufferEnd - _this->Push;
    
        // 判断是否会到达BufferEnd
        if (temp <= data_size)
        {
            memcpy(_this->Push, from, temp);
            from += temp;
            temp = data_size - temp;
            memcpy(_this->Buffer, from, temp);
            _this->Push = _this->Buffer + temp;
        }
        else  // 不需要回到Buffer头部
        {
            memcpy(_this->Push, from, data_size);
            _this->Push += data_size;
        }
            
        _this->PushSize += data_size;
        result = data_size;
    }

    return result;
}

/**
 * @brief 预览数据
 * @param _this 
 * @param to 缓存地址
 * @param data_size 预览数据个数
 * @return Int32 返回有效数据个数
 */
static Int32 L_DoPeek(_TBuffer* _this, Byte* to, Int32 data_size)
{
    Int32 result = 0;
    Int32 avail_size = L_UsedSize(_this);
    if (avail_size > 0)
    {
        if (avail_size < data_size)
            data_size = avail_size;
        Int32 temp = _this->BufferEnd - _this->Pop;

        // 判断是否会到达BufferEnd
        if (temp < data_size)
        {
            memcpy(to, _this->Pop, temp);
            to += temp;
            temp = data_size - temp;
            memcpy(to, _this->Buffer, temp);
        }
        else  // 不需要回到Buffer头部
            memcpy(to, _this->Push, data_size);

        result = data_size;
    }

    return result;
}

/**
 * @brief 弹出数据
 * @param _this 
 * @param to 目标缓存
 * @param data_size 弹出大小
 * @return Int32 实际弹出大小
 */
static Int32 L_DoPop_Memory(_TBuffer* _this, Byte* to, Int32 data_size)
{
    Int32 result = 0;
    Int32 avail_size = L_UsedSize(_this);
    if (avail_size > 0)
    {
        if (avail_size < data_size)
            data_size = avail_size;
        Int32 temp = _this->BufferEnd - _this->Pop;

        // 判断是否会到达BufferEnd
        if (temp <= data_size)
        {
            memcpy(to, _this->Pop, temp);
            to += temp;
            temp = data_size - temp;
            memcpy(to, _this->Buffer, temp);
            _this->Pop = _this->Buffer + temp;
        }
        else  // 不需要回到Buffer头部
        {
            memcpy(to, _this->Pop, data_size);
            _this->Pop += data_size;
        }
            
        _this->PopSize += data_size;
        result = data_size;
    }

    return result;
}

// ---------------- 构造函数和析构函数 ----------------

// 初始化/释放 TZooQueue 对象数据
// 1. TZooQueue_Init 返回的对象就是 data 指针, 且对象必须使用 TZooQueue_Fini 来释放数据;
// 2. 本组函数适用于不分配对象指针情况, 如不分配对象指针的函数局部变量或结构中.
Abc_TRingBuff* Abc_TRingBuffInit(Abc_TRingBuff* data, Byte* buffer, DWord buff_size)
{
    Abc_TRingBuff* result = NULL;

    if (data != NULL && buffer != NULL && buff_size >= 16)
    {
        _TBuffer* _this = (_TBuffer*)data;

        _this->Buffer = buffer;
        _this->BufferEnd = _this->Buffer + buff_size;
        _this->Pop = _this->Push = buffer;
        _this->PopSize = _this->PushSize = 0;
        _this->MaxSize = buff_size;

        result = data;
    }
    return result;
}

void Abc_TRingBuffDone(Abc_TRingBuff* data)
{
    if (data != NULL)
    {
        _TBuffer* _this = (_TBuffer*)data;
        _this->PopSize = _this->PushSize;
    }
}

// Abc_TRingBuff* Abc_TRingBuffCreate(Byte* buffer, Int32 buff_size)
// {
//     _TBuffer* _this = (_TBuffer*)malloc(sizeof(_TBuffer));
//     Abc_TRingBuff* result = Abc_TRingBuffInit((Abc_TRingBuff*)_this, buffer, buff_size);

//     if (result == NULL && _this != NULL)
//         free(_this);
    
//     return result;
// }

// void Abc_TRingBuffFree(Abc_TRingBuff* self)
// {
//     if (self != NULL)
//     {
//         Abc_TRingBuffFini(self);
//         free(self);
//     }
// }

// ---------------- 属性方法 ----------------

// 读取当前已存储的大小
Int32 Abc_TRingBuffSize(Abc_TRingBuff* self)
{
    return L_UsedSize((_TBuffer*)self);
}

// 读取缓存大小
Int32 Abc_TRingBuffMaxSize(Abc_TRingBuff* self)
{
    return ((_TBuffer*)self)->MaxSize;
}

Int32 Abc_TRingBuffPushSize(Abc_TRingBuff* self)
{
    return ((_TBuffer*)self)->PushSize;
}

Int32 Abc_TRingBuffPopSize(Abc_TRingBuff* self)
{
    return ((_TBuffer*)self)->PopSize;
}

Bool Abc_TRingBuffIsFull(Abc_TRingBuff* self)
{
    return L_IsFull((_TBuffer*)self);
}

Bool Abc_TRingBuffIsEmpty(Abc_TRingBuff* self)
{
    return L_IsEmpty((_TBuffer*)self);
}

// ---------------- 公有方法 ----------------

// 数据压入/预读取/弹出缓冲区, 注: 若 data 为 NULL 则返回值为 -1
Int32 Abc_TRingBuffPush(Abc_TRingBuff* self, const Byte* data, Int32 size)
{
    Int32 result = -1;

    if (data != NULL && size >= 0)
    {
        _TBuffer* _this = (_TBuffer*)self;
        result = L_DoPush_Memory(_this, data, size); 
    }

    return result;
}

Int32 Abc_TRingBuffPeek(Abc_TRingBuff* self, Byte* data, Int32 size)
{
    Int32 result = -1;

    if (data != NULL && size >= 0)
    {
        _TBuffer* _this = (_TBuffer*)self;
        result = L_DoPeek(_this, data, size);
    }

    return result;
}

Int32 Abc_TRingBuffPop(Abc_TRingBuff* self, Byte* data, Int32 size)
{
    Int32 result = -1;

    if (data != NULL && size >= 0)
    {
        _TBuffer* _this = (_TBuffer*)self;
        result = L_DoPop_Memory(_this, data, size);
    }

    return result;
}


Int32 Abc_TRingBuffLose(Abc_TRingBuff* self, Int32 size)
{
    Int32 result = 0;

    if (size > 0)
    {
        _TBuffer* _this = (_TBuffer*)self;
        Int32 used_size = L_UsedSize(_this);
        Int32 lose_size = MIN(size, used_size);   // 确定需要丢弃的数据大小
        
        if (lose_size == used_size)
            Abc_TRingBuffClear(self);
        else
        {
            Int32 temp = _this->BufferEnd - _this->Pop;
            // Pop 需要回到 item
            if (temp <= lose_size)  
                _this->Pop = _this->Buffer + (lose_size - temp);
            else    // Pop 不需要回到 item
                _this->Pop += lose_size;
        }
        
        result = lose_size;
    }
    
    return result;
}

Int32 Abc_TRingBuffClear(Abc_TRingBuff* self)
{
    _TBuffer* _this = (_TBuffer*)self;
    Int32 result = _this->PushSize - _this->PopSize;

    _this->PopSize = _this->PushSize;
    _this->Pop = _this->Push;
    
    return result;
}


/*------------------- _TBuffer 类型 end --------------------*/



